// -------------------------------------------------
// BlinKit - BlinKit Library
// -------------------------------------------------
//   File Name: qjs_node_list.cpp
// Description: Bindings for NodeList
//      Author: Ziming Li
//     Created: 2022-03-15
// -------------------------------------------------
// Copyright (C) 2022 MingYang Software Technology.
// -------------------------------------------------

#include "./qjs_bindings.h"

#include "blinkit/blink/renderer/bindings/core/qjs/qjs.h"
#include "blinkit/blink/renderer/bindings/core/qjs/qjs_c_function_list_entries.h"
#include "blinkit/blink/renderer/bindings/core/script_controller.h"
#include "blinkit/blink/renderer/core/dom/node_list.h"

namespace BlinKit {
namespace qjs {

/**
 * https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach
 */
static JSValue ForEach(JSContext *ctx, JSValueConst thisVal, int argc, JSValueConst *argv)
{
    if (!JS_IsFunction(ctx, argv[0]))
        return JS_ThrowTypeError(ctx, "not a function");

    NodeList *nodeList = ScriptWrappable::Cast<NodeList>(thisVal);

    unsigned length = nodeList->length();
    if (0 == length)
        return JS_UNDEFINED;

    ScriptController *scriptController = ScriptController::From(ctx);

    JSValue thisArg = argc > 1 ? argv[1] : JS_UNDEFINED;
    for (unsigned i = 0; i < length; ++i)
    {
        Node *node = nodeList->item(i);

        JSValue args[3];
        args[0] = scriptController->WrapNode(node);
        args[1] = JS_NewUint32(ctx, i);
        args[2] = JS_DupValue(ctx, thisVal);

        JSValue ret = JS_Call(ctx, argv[0], thisArg, 3, args);
        JS_FreeValue(ctx, ret);

        for (JSValue v : args)
            JS_FreeValue(ctx, v);
    }

    return JS_UNDEFINED;
}

static JSValue GetLength(JSContext *ctx, JSValueConst thisVal)
{
    NodeList *nodeList = ScriptWrappable::Cast<NodeList>(thisVal);
    return JS_NewUint32(ctx, nodeList->length());
}

JSValue CreateNodeListPrototype(JSContext *ctx)
{
    static const JSCFunctionListEntry Funcs[] = {
        CFunctionEntry("forEach", 1, ForEach),
        CGetSetEntry(Strings::Length, GetLength, nullptr)
    };

    JSValue ret = JS_NewObject(ctx);
    JS_SetPropertyFunctionList(ctx, ret, Funcs, std::size(Funcs));
    return ret;
}

} // namespace qjs
} // namespace BlinKit
